package carpediem.xin.tamplate.network;

import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import carpediem.xin.tamplate.propertie.CacheProp;
import okhttp3.ResponseBody;
import rx.Subscriber;
import timber.log.Timber;

/**
 * Created by zhaijianwei on 16/12/9.
 */

public abstract class HttpDownloadSubscriber extends Subscriber<ResponseBody> {
    private static String TAG = HttpDownloadSubscriber.class.getSimpleName();
    /*下载控制参数*/
    long fileSizeDownloaded = 0;
    long fileSize = 0;
    Handler handler = new Handler(Looper.getMainLooper());
    /*下载路径及文件*/
    private String mFilePathSaved;
    private File mFile;

    public HttpDownloadSubscriber(@NonNull String filePath, @NonNull String fileName) {
        mFilePathSaved = filePath;
        mFile = new File(mFilePathSaved + File.separator + fileName);
    }

    public HttpDownloadSubscriber(@NonNull String fileName) {
        mFilePathSaved = CacheProp.getDownloadCacheDir().getAbsolutePath();
        mFile = new File(mFilePathSaved + File.separator + fileName);
    }

    public HttpDownloadSubscriber(String mFilePathSaved, File mFile) {
        this.mFilePathSaved = mFilePathSaved;
        this.mFile = mFile;
    }

    /**
     * 获得下载的文件对象
     */
    public File getFile() {
        return mFile;
    }

    @Override
    public void onCompleted() {
        onCompleted(mFile);
    }

    @Override
    public void onError(Throwable e) {
        Timber.tag(TAG).e(e.getMessage());
    }

    @Override
    public void onNext(ResponseBody responseBody) {
        onStarted(mFile);
        writeResponseBodyToDisk(responseBody);
    }

    /**
     * 将返回的数据写入本地文件
     *
     * @param body 服务返回的数据对象
     */
    public boolean writeResponseBodyToDisk(ResponseBody body) {
        try {
            InputStream inputStream = null;
            OutputStream outputStream = null;

            try {
                byte[] fileReader = new byte[4096];

                fileSize = body.contentLength();

                inputStream = body.byteStream();
                outputStream = new FileOutputStream(getFile());

                while (true) {
                    int read = inputStream.read(fileReader);

                    if (read == -1) {
                        break;
                    }

                    outputStream.write(fileReader, 0, read);

                    if (0 == fileSizeDownloaded) {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                onProgress(0, 0, fileSize);
                            }
                        });
                    }
                    fileSizeDownloaded += read;
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            onProgress(fileSizeDownloaded * 1.0f / fileSize, fileSizeDownloaded, fileSize);
                        }
                    });
                }

                outputStream.flush();
                return true;
            } catch (final IOException e) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        onError(e);
                    }
                });
                return false;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (final IOException e) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    onError(e);
                }
            });
            return false;
        }
    }

    /*Override functions*/
    public abstract void onCompleted(File file);

    public abstract void onProgress(double progress, long downloadByte, long totalByte);

    public abstract void onStarted(File file);
}
